package sql

import (
	"strings"

	"vitess.io/vitess/go/sqltypes"

	"vitess.io/vitess/go/mysql/collations"

	"gopkg.in/src-d/go-errors.v1"
	"vitess.io/vitess/go/vt/proto/query"
)

var (
	// ErrUnexpectedType is thrown when a received type is not the expected
	ErrUnexpectedType = errors.NewKind("value at %d has unexpected type: %s")
)

// Schema is the definition of a table.
type Schema []*Column

func (s *Schema) Append(col *Column) *Schema {
	*s = append(*s, col)
	return s
}

func (s Schema) CreateRow() *Row {
	return &Row{
		schema:   s,
		values:   make([]interface{}, len(s)),
		capacity: len(s),
		position: 0,
	}
}

func (s Schema) ToFields() []*query.Field {
	fields := make([]*query.Field, len(s))
	for i, c := range s {
		var charset uint32 = collations.CollationUtf8ID
		if c.Type == sqltypes.Binary || c.Type == sqltypes.VarBinary || c.Type == sqltypes.Blob {
			charset = collations.CollationBinaryID
		}
		fields[i] = &query.Field{
			Name:    c.Name,
			Type:    c.Type,
			Charset: charset,
		}
	}
	return fields
}

func (s Schema) GetColumn(i int) *Column {
	return s[i]
}

// Contains returns whether the schema contains a column with the given name.
func (s Schema) Contains(column string, source string) bool {
	return s.IndexOf(column, source) >= 0
}

// IndexOf returns the index of the given column in the schema or -1 if it's
// not present.
func (s Schema) IndexOf(column, source string) int {
	column = strings.ToLower(column)
	source = strings.ToLower(source)
	for i, col := range s {
		if strings.ToLower(col.Name) == column && strings.ToLower(col.Source) == source {
			return i
		}
	}
	return -1
}

// Equals checks whether the given schema is equal to this one.
func (s Schema) Equals(s2 Schema) bool {
	if len(s) != len(s2) {
		return false
	}

	for i := range s {
		if !s[i].Equals(s2[i]) {
			return false
		}
	}

	return true
}

// HasAutoIncrement returns true if the schema has an auto increment column.
func (s Schema) HasAutoIncrement() bool {
	for _, c := range s {
		if c.AutoIncrement {
			return true
		}
	}

	return false
}

func IsKeyless(s Schema) bool {
	for _, c := range s {
		if c.PrimaryKey {
			return false
		}
	}

	return true
}
